#include <bits/types/struct_timeval.h>
#include <fenv.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdatomic.h>
#include "somb.h"
#include <sys/time.h>

void run_mem_client_client_listen_method_onvailable_cb(uint32_t ServiceId,bool bAvailable)
{
    printf("run_mem_client client listen method callback, recv serviceid=%08x is onvailbe=%d\n",ServiceId,bAvailable);

}

static struct timeval event_total_time = {0}; 
static struct timeval event_start_time = {0}; 
static struct timeval event_end_time = {0}; 
static atomic_int event_total_count = 0;
void run_mem_client_client_listen_event_cb(uint32_t ServiceId,void*EvtData,uint32_t EvtDataLen)
{

    int index = atomic_fetch_add(&event_total_count, 1);

    if(index >= 999)
    {
        memcpy(&event_start_time, EvtData, sizeof(struct timeval));
        gettimeofday(&event_end_time, NULL);
        
        timersub(&event_end_time, &event_start_time, &event_total_time);
        event_total_count = 0;
        printf("event total cost: %ld.%06ld\n", event_total_time.tv_sec, event_total_time.tv_usec);
    }
}

void add_listen_service(void)
{
    int32_t ret;
    ST_SOMB_SERVICE_LISTEN_INFO stServiceListenInfo[] =
    {
        {
            .ServiceId= 0x01010000,
            .ServiceType = SOMB_SVC_TYPE_METHOD,
            .OnAvailableCB = run_mem_client_client_listen_method_onvailable_cb,
        },
        {
            .ServiceId= 0x01010001,
            .ServiceType = SOMB_SVC_TYPE_METHOD,
            .OnAvailableCB = run_mem_client_client_listen_method_onvailable_cb,
        },
        {
            .ServiceId= 0x01010002,
            .ServiceType = SOMB_SVC_TYPE_METHOD,
            .OnAvailableCB = run_mem_client_client_listen_method_onvailable_cb,
        },
        {
            .ServiceId= 0x01010003,
            .ServiceType = SOMB_SVC_TYPE_EVENT,
            .ListenerFlags = SOMB_SVC_FLAGS_EVENT_LISTEN_SYNC_DATA, //this flags means the event data will sync to you when it is deployed by it's provider
            .ListenerCB = run_mem_client_client_listen_event_cb,
        },

    };


    ret = i32SOMB_ServiceListener_Add(stServiceListenInfo, 4);
    if(0 != ret)
    {
        printf("run_mem_client service listener add failed\n");
    }
    else
    {
        printf("run_mem_client service listener add success\n");
    }

}


static struct timeval async_total_time = {0};
static struct timeval async_start_timeval = {0};
static struct timeval async_end_timeval = {0};
static atomic_int async_feedback_count = 0;
void async_callback(uint32_t ServiceId,void*MthRespData,uint32_t MthRespDataLen)
{
    int index = atomic_fetch_add(&async_feedback_count, 1);
    //printf("%d ",index);


    if(index >= 999)
    {
        gettimeofday(&async_end_timeval, NULL);

        timersub(&async_end_timeval, &async_start_timeval, &async_total_time);

        printf("async receive finish, cost: %ld.%06ld\n", async_total_time.tv_sec, async_total_time.tv_usec);

        memset(&async_total_time, 0 ,sizeof(struct timeval));
        async_feedback_count = 0;
        memset(&async_start_timeval, 0 ,sizeof(struct timeval));
        memset(&async_end_timeval, 0 ,sizeof(struct timeval));
    } 
        
}

void print_usage(void)
{
    printf("1: request sync test \n");
    printf("2: request async test\n");
    printf("3: set_request test\n");
}
int main(void)
{
    uint32_t SubNsId;
    int32_t ret = i32SOMB_SubNs_Init(&SubNsId);
    if(SOMB_OK != ret)
    {
        printf("consumer somb sub ns init failed\n");
        return -1;
    }
    printf("SubNs=%d SOMB Init success\n",SubNsId);

    add_listen_service();
    while(1)
    {
        print_usage();
        printf("chose your test index:\n");
        int cmd;
        scanf("%d",&cmd);
        printf("your chose is %d \n",cmd);
        switch(cmd)
        {
            case 1:  // request sync test
                {
                    printf("input payload lentgh:\n");
                    int length;
                    scanf("%d",&length);
                    printf("payload length= %d \n", length);

                    uint8_t * request_data = malloc(length);
                    uint8_t * response_data = malloc(length);

                    uint32_t response_data_len = length;
                    struct timeval start={0}, end={0}, result={0};
                    gettimeofday(&start, NULL);
                    for(int loop = 0; loop < 1000; loop ++)
                    {
                        ret = i32SOMB_Method_Request_Sync(0x01010001, request_data , length, response_data , &response_data_len, 100);
                        if(SOMB_OK != ret)
                        {
                            printf("request sync test failed, ret=%d\n",ret);
                            break;
                        }
                        else{
                            if(response_data_len != length)
                            {
                                printf("request sync test failed length error, ret=%d\n",ret);
                                break;
                            }
                        }
                    }
                    gettimeofday(&end, NULL);

                    timersub(&end, &start, &result);
                    printf("total cost: %ld.%06ld\n",result.tv_sec, result.tv_usec);

                    uint64_t total_usec = result.tv_sec*1000000 + result.tv_usec;
                    uint64_t average_usec = total_usec/1000;

                    printf("average cost: %ld.%06ld\n",average_usec/1000000 , average_usec%1000000);
                    free(request_data);
                    free(response_data);
                }
                break;
            case 2: //request async test
                {
                    int length = 0;
                    printf("input payload lentgh:\n");
                    scanf("%d",&length);
                    printf("payload length= %d \n", length);

                    uint8_t * request_data = malloc(length);

                    gettimeofday(&async_start_timeval, NULL);
                    for(int loop = 0; loop < 1000; loop ++)
                    {
                        //memcpy(request_data, &(async_timeval[loop]), sizeof(struct timeval));
                        i32SOMB_Method_Request_Async(0x01010001, request_data , length, async_callback);
                    }
                    free(request_data);
                }
                break;
            case 3: // setrequest test
                {
                    int length = 0;
                    printf("input payload lentgh:\n");
                    scanf("%d",&length);
                    printf("payload length= %d \n", length);

                    uint8_t * request_data = malloc(length);

                    for(int loop = 0; loop < 1000; loop ++)
                    {
                        gettimeofday((struct timeval *)request_data, NULL);
                        i32SOMB_Method_SetRequest(0x01010002, request_data , length);
                    }
                    free(request_data);
                }
                break;
            default:
                break;
        }

    }

    return 0;
}
